/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package umled.generator;

import java.io.*;
import java.util.*;

import umled.model.*;

/**
 *
 * @author ANor
 */
public class JavaGenerator implements Generator {
    public void process(UMLModel model , String path ){
       path += model.getName();
       File projDir = new File( path );
       projDir.mkdir();
       for( UMLPackage pack : model.getInnerPackages() )
           createPackage( pack , path );
       for( UMLType type : model.getTypes() )
           createType( type, path );
    }
    private void createPackage( UMLPackage pack , String path ){
       path += "\\" + pack.getName();
       File packDir = new File( path );
       packDir.mkdir();
       for( UMLPackage p : pack.getInnerPackages() )
           createPackage( p , path );
       for( UMLType type : pack.getTypes() )
           createType( type, path );
    }
    private void createType( UMLType type, String path ){
       path += "\\" + type.getName() + ".java";
       try{
           File file = new File( path );
           FileWriter out = new FileWriter( file );
           if( type instanceof UMLClass )
               createClass( (UMLClass) type, out );
           else if( type instanceof UMLInterface )
                    createInterface( (UMLInterface) type, out );
       }
       catch(FileNotFoundException e){
           e.printStackTrace();
       }
       catch(IOException e){
           e.printStackTrace();
       }
    }
    private void createClass( UMLClass type, Writer out ){
        PrintWriter pwriter = new PrintWriter( out );
        pwriter.println();
        pwriter.println("//code was generated by UMLEd");
        pwriter.println();
        
        //Full name of current package
        StringBuffer sb = new StringBuffer();
        UMLElement elem = type.getParent();
        sb.append( elem.getName() + ";" );
        elem = elem.getParent();
        while( elem != null ){
            sb.insert( 0, elem.getName() + "." );
            elem = elem.getParent();
        }
        pwriter.println( "package " + sb.toString() );
        pwriter.println();
        
        //TODO imports
        
        //class header
        sb = new StringBuffer();
        sb.append( type.getVisible().toString2() );
        sb.append( " " );
        if( type.isAbstract() )
            sb.append( "abstract " );
        sb.append( "class " ).append( type.getName() );
        UMLClass baseClass = getBaseClass( type.getBaseTypes() );
        if ( baseClass != null )
            sb.append( " extends " ).append( baseClass.getName() ).append(  " " );
        type.removeBaseType( baseClass );
        List<UMLType> interfaces = type.getBaseTypes();
        if( interfaces.size() != 0 ){
            sb.append( " implements ");
            for( UMLType currentInterface : interfaces )
                sb.append( currentInterface.getName() ).append( ", " );
            sb.delete( sb.length() - 2 , sb.length() - 1 );
        }
        type.addBaseType( baseClass );
        sb.append( " {");
        pwriter.println( sb );
        
        for( UMLData data : type.getData() )
            pwriter.println( getJavaStringOfData( data ) );
        pwriter.println();
        
        for( UMLMethod method : type.getMethods() )
            pwriter.println( getJavaStringOfMethod( method ) );
        pwriter.println( "}" );
        pwriter.close();
    }
    private void createInterface( UMLInterface type, Writer out ){
        PrintWriter pwriter = new PrintWriter( out );
        pwriter.println("//code was generated by UMLEd");
        pwriter.println();
        
        //Full name of current package
        StringBuffer sb = new StringBuffer();
        UMLElement elem = type.getParent();
        sb.append( elem.getName() + ";" );
        elem = elem.getParent();
        while( elem != null ){
            sb.insert( 0, elem.getName() + "." );
            elem = elem.getParent();
        }
        pwriter.println( "package " + sb.toString() );
        pwriter.println();
        
        //TODO imports
        
        //interface header
        sb = new StringBuffer();
        sb.append( type.getVisible().toString2() );
        sb.append( " " );
        sb.append( "interface " ).append( type.getName() );
        pwriter.println( sb );
        pwriter.close();
    }
    private String getJavaStringOfData( UMLData data ){
        StringBuffer sbuffer = new StringBuffer();
        sbuffer.append( "\t" ).append( data.getVisible().toString2() );
        sbuffer.append( " " ).append( data.getType().getName() ).append( " " );
        sbuffer.append( data.getName() );
        if ( ! data.getDefoultValue().equals( "" ) )
            sbuffer.append( " = ").append( data.getDefoultValue() );
        sbuffer.append( ";" );
        return sbuffer.toString();
    }
    private String getJavaStringOfMethod( UMLMethod method ){
        StringBuffer sbuffer = new StringBuffer();
        sbuffer.append( "\t" ).append( method.getVisible().toString2() );
        if( method.isStatic() ){
            if( method.isAbstract() )
                throw new RuntimeException();
            sbuffer.append( " static " );
        }else if( method.isAbstract() )
                  sbuffer.append( " abstract " );
              else 
                  sbuffer.append( " " );
        sbuffer.append( method.getReturnType().getName() ).append( " " );
        sbuffer.append( method.getName() ).append( "(" );
        
        List<UMLType> params = method.getParams();
        if( params != null){
            for(int i = 0 ; i < params.size() - 1  ; i++ ){
                sbuffer.append( " " ).append( params.get( i ).getName() ).append( " par" );
                sbuffer.append( i ).append( "," );
            }
            sbuffer.append( " " ).append( params.get( params.size() - 1 ).getName() );
            sbuffer.append( " par" ).append( params.size() - 1 ).append( " )" );
        }
        else
            sbuffer.append( ")" );
        
        if ( method.isAbstract() )
            sbuffer.append( ";" );
        else
            sbuffer.append( "{\n\t\n\t}" );
        return sbuffer.toString();
    }
    private UMLClass getBaseClass( List<UMLType> types ){
        UMLClass baseClass = null;
        for( UMLType type : types )
            if( type instanceof UMLClass )
                if( baseClass == null )
                    baseClass = (UMLClass) type;
                else
                    throw new RuntimeException();
        return baseClass;
    }
    public static void main(String[] args){
        JavaGenerator jgen = new JavaGenerator();
        UMLModel model = TestModel.getTestModel();
        jgen.process( model , "D:\\" );
    }
}
